package com.zy.nft_system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zy.nft_system.domain.Account;
import com.zy.nft_system.domain.Result;
import com.zy.nft_system.domain.User;
import com.zy.nft_system.domain.UserAuth;

import com.zy.nft_system.domain.dto.UserDto;
import com.zy.nft_system.domain.dto.UserInfo;
import com.zy.nft_system.exception.MyException;
import com.zy.nft_system.mapper.AccountMapper;
import com.zy.nft_system.mapper.UserAuthMapper;

import com.zy.nft_system.service.UserService;
import com.zy.nft_system.mapper.UserMapper;

import com.zy.nft_system.utils.DateUtils;
import com.zy.nft_system.utils.JWTUtils;
import com.zy.nft_system.utils.MailUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import java.util.UUID;

/**
* @author 这是那头猪？
* @description 针对表【t_user(用户信息表)】的数据库操作Service实现
* @createDate 2022-09-28 12:20:39
*/
@Service
@Slf4j
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Resource
    UserMapper userMapper;
    @Resource
    AccountMapper accountMapper;
    @Resource
    UserAuthMapper userAuthMapper;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Override
    @Transactional(rollbackFor = MyException.class,propagation = Propagation.REQUIRED)
    public Result regist(User user) {
        //判断用户 密码是否为空
        if (user.getName() == null || user.getPassword() == null) {
            log.info("请输入账户，和密码");
            throw new MyException("请输入账户和密码");
        }
        //判断用户密码是否是空串
        if (user.getName() == "" || user.getPassword() == "") {
            log.info("请输入账户，和密码");
            throw new MyException("请输入账户和密码");
        }
        //先判断用户是否注册
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("name",user.getName());
        List<User> users = userMapper.selectList(userQueryWrapper);
        if (!(users.isEmpty() && users.size()==0)) {
            log.info("用户已存在注册失败");
            throw new MyException("用户已经存在注册失败");
        }
        //用户不存在进行注册
        //对密码进行加密
        String password = user.getPassword();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        //注册用户信息
        int i = userMapper.insert(user);
        if (i != 1) {
            log.info("网络原因，用户注册失败");
            throw new MyException("网络原因，用户注册失败");
        }
        log.info("用户注册成功");
        List<User> users1 = userMapper.selectList(userQueryWrapper);
        User user1 = users1.get(0);

        //注册用户账号
        Account account = new Account();
        account.setAccountid(UUID.randomUUID().toString().replace("-", ""));
        account.setUid(user1.getId());
        int i1 = accountMapper.insert(account);
        if (i1 != 1) {
            log.info("网络原因，用户注册失败");
            throw new MyException("网络原因，用户注册失败");
        }

        //注册用户权限信息
        UserAuth userAuth = new UserAuth();
        userAuth.setUid(user1.getId());
        int insert = userAuthMapper.insert(userAuth);
        if (insert != 1) {
            log.info("网络原因，用户注册失败");
            throw new MyException("网络原因，用户注册失败");
        }
        log.info("用户权限注册成功");
        return Result.success("用户注册成功",null);
    }

    @SneakyThrows
    @Override
    @Transactional(rollbackFor = MyException.class,propagation = Propagation.REQUIRED)
    public Result login(User user, HttpServletRequest request) {
        //判断用户 密码是否为空
        if (user.getName() == null || user.getPassword() == null) {
            log.info("请输入账户，和密码");
            return Result.error("请输入账户和密码");
        }
        //判断用户密码是否是空串
        if (user.getName() == "" || user.getPassword() == "") {
            log.info("请输入账户，和密码");
            return Result.error("请输入账户和密码");
        }

        // 查询用户是否存在
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        QueryWrapper<User> wrapper = userQueryWrapper.eq("name", user.getName());
        User user1 = userMapper.selectOne(wrapper);
        if (user1 == null) {
            log.info("用户密码错误");
            return Result.error("用户密码错误");
        }

        //查询用户是否已尽登录
        // HashMap loginInfo = (HashMap) request.getSession().getAttribute("userInfo" + user1.getId().toString());
        String loginInfo = stringRedisTemplate.opsForValue().get("userInfo" + user1.getId().toString());
        if (loginInfo != null) {
            log.info("用户已经在别处登录，或者没安全退出，请等5分钟再登录");
            return Result.error("用户已经在别处登录，或者没安全退出，请等5分钟再登录");
        }

        //用户存在验证密码
        String password = user1.getPassword();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean matches = bCryptPasswordEncoder.matches(user.getPassword(), password);
        if (!matches) {
            //密码错误的情况
            log.info("用户密码错误");
            return Result.error("用户密码错误");
        }
        //密码正确的情况
        //更具用户id查询到用户账户信息
        QueryWrapper<Account> accountQueryWrapper = new QueryWrapper<Account>().eq("uid", user1.getId());
        Account account = accountMapper.selectOne(accountQueryWrapper);
        //更具用户id查询到用户权限信息
        QueryWrapper<UserAuth> authQueryWrapper = new QueryWrapper<UserAuth>().eq("uid", user1.getId());
        UserAuth userAuth = userAuthMapper.selectOne(authQueryWrapper);
        if(userAuth.getStatus() == 0){
            log.info("用户状态异常，请联系管理员");
            return Result.error("用户状态异常，请联系管理员");
        }
        log.info("密码正确，登录成功");
        //将用户信息生成token存到应用域
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("userId"+user1.getId().toString(),user1.getId().toString());
        hashMap.put("userName"+user1.getId().toString(),user1.getName());
        //更具用户id和name生成token
        String token = JWTUtils.getToken(hashMap, 60 * 30);
        hashMap.put("userAuth"+user1.getId().toString(),userAuth.getAuth().toString());
        hashMap.put("userStatus"+user1.getId().toString(),userAuth.getStatus().toString());
        hashMap.put("token"+user1.getId().toString(),token);
        // //存到应用域
        // request.getSession().setAttribute("userInfo"+user1.getId().toString(),hashMap);
        //存到redis
        stringRedisTemplate.opsForValue().setIfAbsent("userInfo"+user1.getId().toString(), String.valueOf(hashMap), Duration.ofMinutes(5));
        //封装返回的user信息和token信息
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId",user1.getId());
        map.put("userName", user1.getName());
        map.put("userAuth",userAuth.getAuth());
        map.put("userStatus",userAuth.getStatus());
        map.put("token",token);
        map.put("userInfo",user1);
        return Result.success("登录成功",map);
    }


    @Override
    public Result loginOut(User user, HttpServletRequest request) {
        //更具用户名查用户id
        User one = userMapper.selectOne(new QueryWrapper<User>().eq("name", user.getName()));
        try {
            // request.getSession().removeAttribute("userInfo"+one.getId());
            stringRedisTemplate.delete("userInfo"+one.getId());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("用户已经退出，请不要重复退出");
        }
        log.info("用户退出成功");
        return Result.success("用户退出成功",null);

    }

    @Override
    public Result userInfo(int id) {
        log.info("更具用户id查询用户成功");
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("id", id));
        return Result.success("查询成功",user);
    }

    @Override
    public Result setUserInfo(User user) {
        //添加修改日期
        user.setModiftime(DateUtils.dataFormat(new Date()));
        int i = userMapper.update(user, new QueryWrapper<User>().eq("id", user.getId()));
        if (!(i == 1)) {
            log.info("修改用户信息失败");
            return Result.error("修改用户信息失败");
        }
        log.info("修改用户信息成功");
        return Result.success("修改用户信息成功",null);
    }

    @Override
    public Result setUserPwd(UserDto userDto , HttpServletRequest request) {
        //更具name查询用户信息
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("name", userDto.getName()));
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        boolean matches = bCryptPasswordEncoder.matches(userDto.getOldPwd(), user.getPassword());
        if (!matches) {
            log.info("修改用户密码失败，旧密码错误");
            return Result.error("请输入正确的旧用户密码");
        }
        //将新密码编码并存到user对象中
        String encode = bCryptPasswordEncoder.encode(userDto.getYearPwd());
        //修改用户的密码
        user.setPassword(encode);
        //更新用户修改时间
        user.setModiftime(DateUtils.dataFormat(new Date()));
        int i = userMapper.updateById(user);
        if (!(i == 1)) {
            log.info("未知原因修改用户密码失败");
            return Result.error("未知原因修改用户密码失败");
        }
        //清除应用域信息
        // request.getSession().removeAttribute("userInfo"+user.getId());
        stringRedisTemplate.delete("userInfo"+user.getId());
        log.info("用户密码修改成功，应用域清理成功");
        return Result.success("用户密码修改成功,请重新登录",null);
    }
    //从配置文件中注入文件上传的路径
    @Value("${imgPath}")
    private String basePath;

    @Override
    public Result setUserImg(MultipartFile file,String name) {
        //file是一个临时文件，需要转存到指定位置，否则本次请求完成后临时文件会删除

        //原始文件名,和获取文件名后缀
        String originalFilename = file.getOriginalFilename();//abc.jpg
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //使用UUID重新生成文件名，防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID().toString() + suffix;//dfsdfdfd.jpg

        //创建一个目录对象
        //basePath是文件目录，可以在配置文件中指定，然后注入@Value注入变量basePath中
        File dir = new File(basePath);
        //判断当前目录是否存在
        if(!dir.exists()){
            //目录不存在，需要创建
            dir.mkdirs();
        }

        try {
            //将临时文件转存到指定位置
            file.transferTo(new File(basePath + fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("name", name));
        user.setAvatar("/User-Img/"+fileName);
        user.setModiftime(DateUtils.dataFormat(new Date()));
        int i = userMapper.update(user, new QueryWrapper<User>().eq("name", name));
        if (i != 1) {
            return Result.error("未知原因用户修改头像失败");
        }
        log.info("{}修改头像成功",name);
        log.info("头像上传成功路径为{}",basePath+fileName);
        return Result.success("头像修改成功",fileName);
    }

    @Override
    public Result queryUserList(String name, String iphone, Integer status) {
        List<UserInfo> userInfos=userMapper.queryUserList(name,iphone,status);
        log.info("查询用户信息成功");
        return Result.success("查询成功",userInfos);
    }

    @Override
    public Result uploadUserImg(MultipartFile file) {
        //file是一个临时文件，需要转存到指定位置，否则本次请求完成后临时文件会删除

        //原始文件名,和获取文件名后缀
        String originalFilename = file.getOriginalFilename();//abc.jpg
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //使用UUID重新生成文件名，防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID().toString() + suffix;//dfsdfdfd.jpg

        //创建一个目录对象
        //basePath是文件目录，可以在配置文件中指定，然后注入@Value注入变量basePath中
        File dir = new File(basePath);
        //判断当前目录是否存在
        if(!dir.exists()){
            //目录不存在，需要创建
            dir.mkdirs();
        }

        try {
            //将临时文件转存到指定位置
            file.transferTo(new File(basePath + fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("头像上传成功路径为{}",basePath+fileName);
        return Result.success("头像修改成功",fileName);
    }

    @Override
    public Result insertUser(UserInfo userInfo) {
        //判断用户 密码是否为空
        if (userInfo.getName() == null || userInfo.getPassword() == null) {
            log.info("请输入账户，和密码");
            return Result.error("请输入账户和密码");
        }
        //判断用户密码是否是空串
        if (userInfo.getName() == "" || userInfo.getPassword() == "") {
            log.info("请输入账户，和密码");
            return Result.error("请输入账户和密码");
        }
        //先判断用户是否注册
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("name",userInfo.getName());
        List<User> users = userMapper.selectList(userQueryWrapper);
        if (!(users.isEmpty() && users.size()==0)) {
            log.info("用户已存在注册失败");
            return Result.error("用户已存在注册失败");
        }
        //用户不存在进行注册
        //对密码进行加密
        String password = userInfo.getPassword();
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(userInfo.getPassword());
        userInfo.setPassword(encode);
        userInfo.setCreatetime(DateUtils.dataFormat(new Date()));
        //注册用户信息
        int i = userMapper.insert(userInfo);
        if (i != 1) {
            log.info("网络原因，用户注册失败");
            return Result.error("网络原因，用户注册失败");
        }
        log.info("用户注册成功");
        List<User> users1 = userMapper.selectList(userQueryWrapper);
        User user1 = users1.get(0);

        //注册用户账号
        Account account = new Account();
        account.setAccountid(UUID.randomUUID().toString().replace("-", ""));
        account.setUid(user1.getId());
        int i1 = accountMapper.insert(account);
        if (i1 != 1) {
            log.info("网络原因，用户注册失败");
            return Result.error("网络原因，用户注册失败");
        }

        //注册用户权限信息
        UserAuth userAuth = new UserAuth();
        userAuth.setUid(user1.getId());
        userAuth.setStatus(userInfo.getStatus());
        userAuth.setAuth(userInfo.getAuth());
        int insert = userAuthMapper.insert(userAuth);
        if (insert != 1) {
            log.info("网络原因，用户注册失败");
            return Result.error("网络原因，用户注册失败");
        }
        log.info("用户权限注册成功");
        return Result.success("用户注册成功",null);
    }

    @Override
    public Result queryUser(int id) {
        log.info("查询成功");
        UserInfo userInfo = userMapper.queryUser(id);
        if (userInfo == null) {
            log.info("查询用户失败，不存在该用户");
            return Result.error("查询用户失败，不存在该用户");
        }
        return Result.success("查询成功",userInfo);
    }

    @Override
    public Result deleteUser(int id) {
        int id1 = userMapper.delete(new QueryWrapper<User>().eq("id", id));
        if (id1 != 1) {
            return Result.error("未知原因删除失败");
        }
        log.info("用户信息删除成功");
        int uid = accountMapper.delete(new QueryWrapper<Account>().eq("uid", id));
        if (uid != 1) {
            return Result.error("未知原因删除失败");
        }
        log.info("用户帐户信息删除成功");
        int i = userAuthMapper.delete(new QueryWrapper<UserAuth>().eq("uid", id));
        if (i != 1) {
            return Result.error("未知原因删除失败");
        }
        log.info("用户权限信息删除成功");
        return Result.success("用户删除成功",null);
    }

    @Override
    public Result updateUserInfo(UserInfo userInfo) {
        User user = new User();
        user.setId(userInfo.getId());
        user.setName(userInfo.getName());
        user.setAge(userInfo.getAge());
        user.setSex(userInfo.getSex());
        user.setEmil(userInfo.getEmil());
        user.setIphone(userInfo.getIphone());
        user.setAvatar(userInfo.getAvatar());
        user.setModiftime(DateUtils.dataFormat(new Date()));
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encode = null;
        try {
            encode = encoder.encode(userInfo.getPassword());
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("新密码不能为空");
        }
        user.setPassword(encode);

        int update = 0;
        try {
            update = userMapper.update(user, new QueryWrapper<User>().eq("id", user.getId()));
        } catch (Exception e) {
            e.printStackTrace();
            return Result.error("用户名或邮箱已存在，请重新输入");
        }
        if (update != 1) {
            log.info("修改失败");
            return Result.error("未知原因用户信息修改失败");
        }
        log.info("用户信息修改成功");
        UserAuth userAuth = new UserAuth();
        userAuth.setModiftime(DateUtils.dataFormat(new Date()));
        userAuth.setStatus(userInfo.getStatus());
        userAuth.setAuth(userInfo.getAuth());
        userAuth.setUid(userInfo.getId());
        int update1 = userAuthMapper.update(userAuth, new QueryWrapper<UserAuth>().eq("uid", userAuth.getUid()));
        if (update1 != 1) {
            log.info("修改失败");
            return Result.error("未知原因用户信息修改失败");
        }
        log.info("用户权限信息修改成功");
        return Result.success("用户信息修改成功",null);
    }

    @Override
    public Result queryManageUser(boolean emil) {
        List<HashMap> userNames=userMapper.queryManageUser();
        if (emil){
            //给所有的管理员发邮件通知有人找
            for (HashMap map: userNames){
                boolean sendMail = MailUtils.sendMail(map.get("emil").toString() ,"管理员有用户找", "nft系统邮件");
                log.info("邮件发送{}", sendMail);
            }
            return Result.success("邮件发送成功,管理员正在赶来的路上", null);
        }
        String[] users=new String[userNames.size()];
        for (int i = 0; i < userNames.size(); i++) {
            users[i]= (String) userNames.get(i).get("name");
        }
        log.info("查询成功");
        return Result.success("查询成功", JSON.toJSONString(users));
    }

    @Override
    public Result updateUserStatus(UserInfo userInfo) {
        UserAuth userAuth = new UserAuth();
        userAuth.setUid(userInfo.getId());
        userAuth.setStatus(userInfo.getStatus());
        userAuth.setModiftime(DateUtils.dataFormat(new Date()));
        int update = userAuthMapper.update(userAuth, new QueryWrapper<UserAuth>().eq("uid", userAuth.getUid()));
        if (update != 1) {
            log.info("修改失败");
            return Result.error("修改失败");
        }
        User user = new User();
        user.setModiftime(DateUtils.dataFormat(new Date()));
        user.setId(userInfo.getId());
        int update1 = userMapper.update(user, new QueryWrapper<User>().eq("id", user.getId()));
        if (update1 != 1) {
            log.info("修改失败");
            return Result.error("修改失败");
        }
        log.info("修改成功");
        return Result.success("修改成功",null);
    }

}




